/****************************************************************************
 * @date 2018-02-23  The file contains all ecc soft error  recover realization.
 *
 * Copyright:    (c)2017 Centec Networks Inc.  All rights reserved.
 *
 * Modify History:
 * Revision:     v0.1
 * Date:         2018-02-23
 * Reason:       Create for USW v3.0
 ****************************************************************************/
#include "sal.h"
#include "usw/include/drv_io.h"
#include "usw/include/drv_app.h"
#include "usw/include/drv_ser.h"
#include "usw/include/drv_sdb.h"
#include "usw/include/drv_ftm.h"

#define DRV_ECC_SCAN_MODE_ONCE      0
#define DRV_ECC_SCAN_MODE_CONTINUE  1
#define DRV_ECC_SCAN_MODE_STOP      2

#define DRV_ECC_LPM_AD_BLOCK_NUM 2
#define DRV_ECC_LPM_KEY_BLOCK_NUM 4
#define DRV_ECC_MPLS_HS_KEY_ECC_SIZE  64
#define DRV_ECC_SHARE_BUFFER_ECC_SIZE 48
#define DRV_ECC_ACC_TBL_MIN_SIZE      12
#define DRV_UINT32_BITS  32
#define _DRV_BMP_OP(_bmp, _offset, _op)     \
    (_bmp[(_offset) / DRV_UINT32_BITS] _op(1U << ((_offset) % DRV_UINT32_BITS)))

#define DRV_BMP_ISSET(bmp, offset)          \
    _DRV_BMP_OP((bmp), (offset), &)

#ifdef SDK_IN_DEBUG_VER
#define DRV_SER_BUFFER_DUMP(name, buffer, size)   \
{\
    uint32 _loop_ = 0;\
    sal_printf(name);\
    do{\
        sal_printf("%08x ", buffer[_loop_]);\
    }while(++_loop_ < (size>>2));\
    sal_printf("\n");\
}
#else
#define DRV_SER_BUFFER_DUMP(name, buffer, size)
#endif

struct key_lookup_result_s
{
   uint32 bucket_index;
};
typedef struct key_lookup_result_s key_lookup_result_t;

struct key_lookup_info_s
{
    uint8* key_data;
    uint32 key_bits;
    uint32 polynomial;
    uint32 poly_len;
    uint32 type;
    uint32 crc_bits;
};
typedef struct key_lookup_info_s key_lookup_info_t;
extern int32 dal_get_chip_number(uint8* p_num);
extern uint32 _drv_usw_hash_calculate_index(key_lookup_info_t * key_info, key_lookup_result_t * key_result);
extern int32 drv_usw_chip_read_sram_entry(uint8 lchip, uint64 addr, uint32* data, int32 len);
uint8 g_drv_ecc_scan_mode[DRV_SER_SCAN_TYPE_NUM];

enum drv_ecc_tbl_type_e
{
    DRV_ECC_TBL_TYPE_UNKNOWN = 0,
    DRV_ECC_TBL_TYPE_STATIC,
    DRV_ECC_TBL_TYPE_HASH_KEY,
    DRV_ECC_TBL_TYPE_DYNAMIC_SRAM = 3,
    DRV_ECC_TBL_TYPE_NUM
};
typedef enum drv_ecc_tbl_type_e drv_ecc_tbl_type_t;


enum drv_ecc_recover_action_e
{
    DRV_ECC_RECOVER_ACTION_NONE,
    DRV_ECC_RECOVER_ACTION_REMOVE,
    DRV_ECC_RECOVER_ACTION_OVERWRITE,
    DRV_ECC_RECOVER_ACTION_NUM
};
typedef enum drv_ecc_recover_action_e drv_ecc_recover_action_t;

extern uint32
drv_sdb_calc_tbl_size(uint8 lchip, uint8 mode);

STATIC uint32
_drv_ser_get_sharebuf_stats(uint8 lchip)
{
    uint32    cmd = 0;
    uint32    dynamic_used = 0;

    cmd = DRV_IOR(ShareBufferCtl_t, ShareBufferCtl_cfgShareTableEn_f);
    DRV_FIELD_IOCTL(lchip, 0, cmd, &dynamic_used);

    return dynamic_used;
}

void
drv_ser_report_ser_event_cb(uint8 lchip, drv_ser_cb_info_t* p_ecc_cb)
{
    uint8 gchip = 0;
    drv_ser_master_t* p_drv_ser_master = NULL;
    p_drv_ser_master = (drv_ser_master_t*)(p_drv_master[lchip]->p_ser_master);

    drv_get_gchip_id(lchip, &gchip);

    if (NULL != p_drv_ser_master->ser_event_cb)
    {
        p_drv_ser_master->ser_event_cb(gchip, p_ecc_cb);
    }

    return;
}

STATIC int32
_drv_ser_get_dyn_entry_size(uint8 lchip, uint8 ram_type, uint8* p_entry_size)
{
    uint8 entry_size_db[DRV_FTM_MEM_SHARE_MEM+1] = {
        0,  0, 48, 48, 48,
        0,  0,  0,  0,  0,
        0,  0,  0,  0,  0,
        0,  0, 24,  8, 64,
       24,  0,  0,  0,  0,
        0,  0, 48
    };

    *p_entry_size = entry_size_db[ram_type];
    return DRV_E_NONE;

}

STATIC int32
_drv_ecc_map_lpm_ad(uint8 lchip, uint8* p_mem_id, uint8* p_mem_order, uint16* p_entry_idx)
{
    uint8 per_blk_entry_size = 0;
    uint32  per_blk_mem_size = 0;
    uint32 per_blk_entry_index = 0;
    uint8 i = 0;
    uint8 mem_id = *p_mem_id;
    uint8 mem_order = *p_mem_order;
    uint8 stat_mem_id = mem_id - mem_order;
    uint32 entry_index_all = 0;

    _drv_ser_get_dyn_entry_size(lchip, DRV_FTM_MEM_TCAM_LPM_AD, &per_blk_entry_size);
    for (i = 0; i < DRV_ECC_LPM_AD_BLOCK_NUM; i++)
    {
        per_blk_mem_size = 0;
        drv_usw_get_memory_size(lchip, stat_mem_id + DRV_ECC_LPM_AD_BLOCK_NUM*mem_order + i, &per_blk_mem_size);
        if ((per_blk_mem_size == 0) || (per_blk_entry_size == 0))
        {
            return DRV_E_INVALID_MEM;
        }

        per_blk_entry_index = per_blk_mem_size / per_blk_entry_size;

        if (*p_entry_idx < entry_index_all + per_blk_entry_index)
        {
            *p_mem_id  =  stat_mem_id + DRV_ECC_LPM_AD_BLOCK_NUM*mem_order + i;
            *p_mem_order = DRV_ECC_LPM_AD_BLOCK_NUM*mem_order + i;
            *p_entry_idx = (*p_entry_idx) - entry_index_all;
            return  DRV_E_NONE;
        }
        entry_index_all += per_blk_entry_index;
    }

    return  DRV_E_NONE;
}

STATIC int32
_drv_ser_restore_static_tbl(uint8 lchip ,drv_ecc_intr_tbl_t* p_intr_info, drv_ser_cb_info_t* p_ecc_cb)
{
    uint32    data[MAX_ENTRY_WORD] = {0};   /*EpeScheduleSopRam*/
    uint32    cmd = 0;
    uint32    err_rec = 0;
    uint32    rec_idx_f = 0;
    uint16    err_tbl_id = 0;
    uint8*    p_bucket_data = NULL;
    uint32    ecc_tbl_idx = 0;
    uint32    entry_offset = 0;
    drv_ser_master_t* p_drv_ser_master = NULL;
    drv_sdb_t* p_sdb = g_sdb_master[lchip];

    p_drv_ser_master = p_drv_master[lchip]->p_ser_master;
    err_tbl_id  =   p_intr_info->mem_id;
    err_rec     =   p_intr_info->rec_id;
    rec_idx_f   =   p_intr_info->rec_id_fld;

    /*get the err_table_index*/
    cmd = DRV_IOR(err_rec, DRV_ENTRY_FLAG);
    DRV_IOCTL(lchip, 0, cmd, data);
    DRV_GET_FIELD(lchip,err_rec, rec_idx_f, data, &ecc_tbl_idx);

    /*for test*/
    if (p_drv_ser_master->simulation_en)
    {
        ecc_tbl_idx = p_drv_ser_master->err_rec_offset;
    }

    /*deal with no-backup-tbl*/
    if (p_drv_master[lchip]->sdb_type < SDB_ALL || DRV_SDB_MODE(err_tbl_id) == SDB_DIS)
    {
        p_ecc_cb->recover  = 0;
        (p_drv_ser_master->ignore_cnt)++;
    }
    else
    {
        p_bucket_data = p_sdb->static_tbl[err_tbl_id];
        if (p_bucket_data == NULL)
        {
            /*if can not get this tbl in backup-data*/
            p_ecc_cb->recover  = 0;
            (p_drv_ser_master->ignore_cnt)++;
        }
        /*recover*/
        entry_offset = DRV_TBL_TCAM_MEM(err_tbl_id)? TABLE_ENTRY_OFFSET(lchip, err_tbl_id): TABLE_ENTRY_SIZE(lchip, err_tbl_id);
        p_bucket_data += ecc_tbl_idx*entry_offset;
        drv_usw_chip_sram_tbl_write(lchip, (tbls_id_t)ecc_tbl_idx, DRV_IOW(err_tbl_id, DRV_ENTRY_FLAG), 0, (uint32*)p_bucket_data);
        p_sdb->read_tbl_from_hw = TRUE;
        drv_usw_chip_sram_tbl_read(lchip, (tbls_id_t)ecc_tbl_idx, DRV_IOR(err_tbl_id, DRV_ENTRY_FLAG), 0, data);
        p_sdb->read_tbl_from_hw = FALSE;
        p_ecc_cb->recover = (sal_memcmp((uint8 *)p_bucket_data, (uint8 *)data, entry_offset)? 2: 1);
        (p_drv_ser_master->recover_static_cnt)++;
    }

    p_ecc_cb->tbl_id     = p_intr_info->mem_id;
    p_ecc_cb->tbl_index  = ecc_tbl_idx;
    p_ecc_cb->type       = p_intr_info->err_type;
    p_ecc_cb->action     = p_intr_info->action;

    return DRV_E_NONE;

}

/* basic access mode, hw_addr use DRV_MEM_ADD0(lchip, mem_id) */
STATIC INLINE uint8
_drv_usw_get_dyn_entry_info(uint8 lchip, uint8 mem_id)
{
    uint8 ecc_entry_size = 0;
    ecc_entry_size = DRV_MEM_ENTRY_SIZE(lchip, mem_id);
    return ecc_entry_size;
}

STATIC int32
_drv_ecc_restore_dynamic_sram(uint8 lchip ,drv_ecc_intr_tbl_t* p_intr_info, drv_ser_cb_info_t* p_ecc_cb)
{
    drv_ser_master_t* p_drv_ser_master = NULL;
    uint8*    p_mem_addr               = NULL;
    uint32    cmd             = 0;
    uint32    err_rec         = 0;
    uint32    rec_idx_f       = 0;
    uint8     err_mem_id      = 0;
    uint8     err_mem_type    = 0;
    uint8     err_mem_order   = 0;
    uint32    err_entry_index = 0;
    uint8     err_entry_size  = 0;
    uint8     err_entry_size_aline = 0;
    uint32    err_mem_offset  = 0;
    uint32*   hw_addr_array;
    uint32     buffer2[128]    = {0};
    drv_ftm_mem_info_t mem_info;
    drv_sdb_t* p_sdb = g_sdb_master[lchip];

    p_drv_ser_master = p_drv_master[lchip]->p_ser_master;
    err_mem_id  =   p_intr_info->mem_id;
    err_rec     =   p_intr_info->rec_id;
    rec_idx_f   =   p_intr_info->rec_id_fld;

    if (!p_drv_ser_master->simulation_en)
    {
        /*get the err_table_index*/
        cmd = DRV_IOR(err_rec, DRV_ENTRY_FLAG);
        DRV_IOCTL(lchip, 0, cmd, buffer2);
        DRV_GET_FIELD(lchip,err_rec, rec_idx_f, buffer2, &err_entry_index);
    }
    else    /*simulation*/
    {
         err_entry_index = p_drv_ser_master->err_rec_offset;
         sal_memset(buffer2, 0, sizeof(buffer2));
    }
    sal_memset(&mem_info, 0, sizeof(drv_ftm_mem_info_t));
    mem_info.info_type = DRV_FTM_MEM_INFO_MEM_TYPE_DETAIL;
    mem_info.mem_id    = err_mem_id;
    DRV_IF_ERROR_RETURN(drv_ftm_get_mem_info(lchip, &mem_info));
    err_mem_type = mem_info.mem_type;
    err_mem_order = mem_info.mem_sub_id;

    /*sharebuffer not used for dynamic will not recover*/
    if (!(p_drv_master[lchip]->dev_type >= DRV_TSINGMA_MX))
    {
        if ((err_mem_type == DRV_FTM_MEM_SHARE_MEM) && (0 == _drv_ser_get_sharebuf_stats(lchip)))
        {
            p_ecc_cb->tbl_id     = 0xFF000000 + err_mem_id;
            p_ecc_cb->tbl_index  = err_mem_offset;
            p_ecc_cb->type       = p_intr_info->err_type;
            p_ecc_cb->action     = p_intr_info->action;
            p_ecc_cb->tbl_id |= (err_entry_size) << 16;
            return DRV_E_NONE;
        }

        if (err_mem_type == DRV_FTM_MEM_TCAM_LPM_AD)/*lpm ad need map mem_id and entry index*/
        {
            uint16 temp = 0;
            _drv_ecc_map_lpm_ad(lchip, &err_mem_id, &err_mem_order, &temp);
            err_entry_index = temp;
        }
    }

    /*get sw data*/
    //drv_usw_ftm_get_sram_info(lchip, err_mem_id, &hw_addr, &mem_entry_num, (uint32*)&err_entry_size);
    err_entry_size = DRV_MEM_ENTRY_SIZE(lchip, err_mem_id);
    DRV_SDB_ENTRY_SIZE_ALINE(err_entry_size, err_entry_size_aline);

    err_mem_offset = err_entry_size_aline * err_entry_index;
    p_mem_addr = p_sdb->dynamic_tbl[err_mem_id] + (err_entry_index * err_entry_size);

    /*Invalid tbl,such as aging/ipfix tbl:do not recover*/
    if (NULL == p_sdb->dynamic_tbl[err_mem_id] || sal_memcmp(p_mem_addr, buffer2, err_entry_size) == 0)
    {
        p_ecc_cb->recover = 0;
        (p_drv_ser_master->ignore_cnt)++;
    }
    else /*rewrite*/
    {
        hw_addr_array = &DRV_MEM_INFO(lchip, err_mem_id).addr_3w;
        p_ecc_cb->recover = 0;
        DRV_IF_ERROR_RETURN(drv_usw_chip_write_sram_entry(lchip, (uintptr)(hw_addr_array[DRV_MEM_ADDR_SEL(lchip, err_mem_id)] + err_mem_offset), (uint32*)p_mem_addr, err_entry_size));
        DRV_IF_ERROR_RETURN(drv_usw_chip_read_sram_entry(lchip, (uintptr)(hw_addr_array[DRV_MEM_ADDR_SEL(lchip, err_mem_id)] + err_mem_offset), (uint32*)buffer2, err_entry_size));
        p_ecc_cb->recover = (sal_memcmp(p_mem_addr, buffer2, err_entry_size)? 2: 1);
        (p_drv_ser_master->recover_dynamic_cnt)++;
    }

    p_ecc_cb->tbl_id     = 0xFF000000 + err_mem_id;
    p_ecc_cb->tbl_index  = err_mem_offset;
    p_ecc_cb->type       = p_intr_info->err_type;
    p_ecc_cb->action     = p_intr_info->action;
    p_ecc_cb->tbl_id |= (err_entry_size) << 16;
    return DRV_E_NONE;

}


#define ___ECC_RECOVER_SCAN___

STATIC void
_drv_ser_scan_sbe_thread(void* param)
{
    uintptr lchip = (uintptr)param;
    drv_ser_cb_info_t  ser_cb_info;
    uint32 i = 0;
    uint32 cmd = 0;
    uint32 val = 0;
    uint32 data[32] = {0};
    drv_ecc_sbe_cnt_t*  p_sbe_cnt = NULL;
    /*char* p_time_str = NULL;
    sal_time_t tm;*/
    drv_ser_master_t* p_drv_ser_master = NULL;

    p_drv_ser_master = (drv_ser_master_t*)(p_drv_master[lchip]->p_ser_master);

    /*sal_time(&tm);
    p_time_str = sal_ctime(&tm);
    DRV_DBG_INFO("\nStart single bit error scan thread time: %s", p_time_str);*/

    p_sbe_cnt = p_drv_master[lchip]->drv_ecc_data.p_sbe_cnt;
    do
    {
        for (i = 0; (MaxTblId_t != p_sbe_cnt[i].rec); i++)
        {
            if (g_drv_ecc_scan_mode[DRV_SER_SCAN_TYPE_SBE] == DRV_ECC_SCAN_MODE_STOP)
            {
                  /*stop scan break the thread*/
                  p_drv_ser_master->scan_interval[DRV_SER_SCAN_TYPE_SBE]  = 0;
                  p_drv_ser_master->scan_doing[DRV_SER_SCAN_TYPE_SBE] = 0;
                  /*DRV_DBG_INFO("\nStop single bit error scan ,scan stop time: %s", p_time_str);*/
                  return;
            }

            p_drv_ser_master->scan_doing[DRV_SER_SCAN_TYPE_SBE] = 1;

            cmd = DRV_IOR(p_sbe_cnt[i].rec, DRV_ENTRY_FLAG);
            sal_memset(data, 0, sizeof(data));
            DRV_IOCTL(lchip, p_sbe_cnt[i].index, cmd, data);
            DRV_GET_FIELD(lchip,p_sbe_cnt[i].rec, p_sbe_cnt[i].fld, data, &val);
            if (val != p_sbe_cnt[i].old_value)
            {
                /*DRV_DBG_INFO("\nscan sbe rec tbl (%d %s),fld:%d,cnt:%d, old value:%d\n", p_sbe_cnt[i].rec, TABLE_NAME(lchip, p_sbe_cnt[i].rec), p_sbe_cnt[i].fld,val, p_sbe_cnt[i].old_value);*/
                ser_cb_info.tbl_id = p_sbe_cnt[i].tblid;
                ser_cb_info.type = DRV_SER_TYPE_SBE;
                ser_cb_info.tbl_index = 0xFFFFFFFF;
                ser_cb_info.recover = 1;
                ser_cb_info.action = DRV_SER_ACTION_LOG;
                ser_cb_info.intr_type = NULL;
                drv_ser_report_ser_event_cb(lchip, &ser_cb_info);
                (p_drv_ser_master->recover_sbe_cnt)++;
            }
            p_sbe_cnt[i].old_value = val;
        }

        p_drv_ser_master->scan_doing[DRV_SER_SCAN_TYPE_SBE] = 0;

        if (g_drv_ecc_scan_mode[DRV_SER_SCAN_TYPE_SBE] == DRV_ECC_SCAN_MODE_CONTINUE)
        {
            sal_task_sleep(p_drv_ser_master->scan_interval[DRV_SER_SCAN_TYPE_SBE]* 60 *1000);
        }
        else
        {
            break;
        }
    }while(1);
    p_drv_ser_master->scan_interval[DRV_SER_SCAN_TYPE_SBE] = 0;

    /*sal_time(&tm);
    p_time_str = sal_ctime(&tm);
    DRV_DBG_INFO("\nSbe scan thread exist time: %s", p_time_str);*/

    return;
}
#if 0
STATIC void
_drv_ser_scan_tcam_thread(void* param)
{
    uintptr lchip = (uintptr)param;
    uint32 i = 0, j = 0, key_index = 0;
    uint32 cmd = 0, per_entry_bytes = 0;
    uint32 entries_interval = 0;
    uint32 data[24] = {0};
    uint32 mask[24] = {0};
    tbl_entry_t tcam_key;
    char* p_time_str = NULL;
    sal_time_t tm;
    drv_ser_master_t* p_drv_ser_master = NULL;
    uint16  (*p_scan_tcam_tbl)[5] = NULL;

    p_scan_tcam_tbl  = p_drv_master[lchip]->drv_ecc_data.p_scan_tcam_tbl;
    p_drv_ser_master = (drv_ser_master_t*)(p_drv_master[lchip]->p_ser_master);
    tcam_key.data_entry = data;
    tcam_key.mask_entry = mask;

    sal_time(&tm);
    p_time_str = sal_ctime(&tm);
    DRV_DBG_INFO("\nStart tcam scan thread time: %s", p_time_str);
    do
    {
        entries_interval = 0;
        for (i = 0; p_scan_tcam_tbl[i][0] != MaxTblId_t; i++)
        {
            drv_ser_db_get_tcam_local_entry_size(lchip, p_scan_tcam_tbl[i][0], &per_entry_bytes);

            for (j = 1; (j < 5) && (MaxTblId_t != p_scan_tcam_tbl[i][j]); j++)
            {
                cmd = DRV_IOR(p_scan_tcam_tbl[i][j], DRV_ENTRY_FLAG);
                for (key_index = 0; key_index < TABLE_MAX_INDEX(lchip, p_scan_tcam_tbl[i][j]); key_index++)
                {
                    if (g_drv_ecc_scan_mode[DRV_SER_SCAN_TYPE_TCAM] == 2)
                    {
                        /*stop scan break the thread*/
                        p_drv_ser_master->scan_interval[DRV_SER_SCAN_TYPE_TCAM]  = 0;
                        p_drv_ser_master->scan_doing[DRV_SER_SCAN_TYPE_TCAM] = 0;
                        DRV_DBG_INFO("\nStop tcam bit error scan ,scan stop time: %s", p_time_str);
                        return;
                    }

                    p_drv_ser_master->scan_doing[DRV_SER_SCAN_TYPE_TCAM] = 1;
                    DRV_IOCTL(lchip, key_index, cmd, &tcam_key);
                    entries_interval += (TCAM_KEY_SIZE(lchip, p_scan_tcam_tbl[i][j]) / per_entry_bytes);
                    /*DRV_DBG_INFO("\nscan tcam tbl:%d,index:%d\n", p_scan_tcam_tbl[i][j],key_index);*/
                    if (entries_interval >= p_drv_ser_master->tcam_scan_burst_entry_num)
                    {
                        p_drv_ser_master->scan_doing[DRV_SER_SCAN_TYPE_TCAM] = 0;
                        sal_task_sleep(p_drv_ser_master->tcam_scan_burst_interval);
                        entries_interval = 0;
                    }
                }
            }
        }
        p_drv_ser_master->scan_doing[DRV_SER_SCAN_TYPE_TCAM] = 0;
        if (g_drv_ecc_scan_mode[DRV_SER_SCAN_TYPE_TCAM] == 1)
        {
            sal_task_sleep(p_drv_ser_master->scan_interval[DRV_SER_SCAN_TYPE_TCAM]* 60 *1000);
        }
        else
        {
            break;
        }
    }while(1);
    p_drv_ser_master->scan_interval[DRV_SER_SCAN_TYPE_TCAM] = 0;

    sal_time(&tm);
    p_time_str = sal_ctime(&tm);
    DRV_DBG_INFO("\nTcam scan thread exist time: %s", p_time_str);

    return;
}
#endif
/**
*mode                        *scan_interval * meanings                                *
*DRV_ECC_SCAN_MODE_ONCE      *-             * scan once                               *
*DRV_ECC_SCAN_MODE_CONTINUE  *n             * loop scan,interval time:n (mins)        *
*DRV_ECC_SCAN_MODE_STOP      *-             * stop scan or no scan enable             *
**/
int32
drv_ser_set_mem_scan_mode(uint8 lchip, drv_ser_scan_type_t type,  uint8 mode, uint32 scan_interval, uint64 cpu_mask)
{
    drv_ser_master_t* p_drv_ser_master = NULL;
    uintptr chip_id = lchip;
    sal_task_t tmp_task;

    p_drv_ser_master = (drv_ser_master_t*)(p_drv_master[lchip]->p_ser_master);

    if ((!p_drv_ser_master) || (SDK_WORK_PLATFORM == 1)
         || ((DRV_SER_SCAN_TYPE_TCAM == type) && (0 == p_drv_ser_master->tcam_scan_en))
         || ((DRV_SER_SCAN_TYPE_SBE == type) && (0 == p_drv_ser_master->sbe_scan_en)))
    {
        return DRV_E_NONE;
    }

    if (mode > 2)
    {
        return DRV_E_INVALID_PARAMETER;
    }

    if (mode != 1)
    {
       scan_interval = (mode == 0)?1:0;
    }

    g_drv_ecc_scan_mode[type] = mode;

    if(DRV_SER_SCAN_TYPE_TCAM == type)
    {
        p_drv_ser_master->scan_interval[type]= scan_interval;
        return DRV_E_NONE;
    }
    /* max32 in ms mean (2^32-1)/60/1000 min*/
    if(scan_interval > 71582)
    {
        return DRV_E_INVALID_PARAMETER;
    }
    if (scan_interval && ((p_drv_ser_master->scan_interval[type]) == 0 ))
    {
        if (p_drv_ser_master->scan_thread[type].p_scan_task)
        {
            sal_task_destroy(p_drv_ser_master->scan_thread[type].p_scan_task);
        }
        sal_memset(&tmp_task, 0, sizeof(sal_task_t));
        tmp_task.cpu_mask = cpu_mask;
        tmp_task.task_type = SAL_TASK_TYPE_ECC_SCAN;
        sal_sprintf(tmp_task.name, "%s-%d", "DrvSbeScan", lchip);
        p_drv_ser_master->scan_thread[type].p_scan_task = &tmp_task;

        sal_task_create(&p_drv_ser_master->scan_thread[type].p_scan_task,
                        tmp_task.name,
                        SAL_DEF_TASK_STACK_SIZE,
                        p_drv_ser_master->scan_thread[DRV_SER_SCAN_TYPE_SBE].prio,
                        _drv_ser_scan_sbe_thread,
                        (void*)chip_id);
    }
    p_drv_ser_master->scan_interval[type]= scan_interval;

    return DRV_E_NONE;
}

int32
drv_ser_get_mem_scan_mode(uint8 lchip ,drv_ser_scan_type_t type, uint8* p_mode, uint32* p_scan_interval)
{
    drv_ser_master_t* p_drv_ser_master = NULL;

    p_drv_ser_master = (drv_ser_master_t*)(p_drv_master[lchip]->p_ser_master);

    /*uml do not init ecc*/
    if (SDK_WORK_PLATFORM == 1)
    {
        return DRV_E_NONE;
    }

    DRV_PTR_VALID_CHECK(p_mode);
    DRV_PTR_VALID_CHECK(p_scan_interval);

    if (NULL == p_drv_ser_master)
    {
        return DRV_E_NONE;
    }

    if (DRV_SER_SCAN_TYPE_TCAM == type)
    {
        *p_scan_interval = p_drv_ser_master->scan_interval[DRV_SER_SCAN_TYPE_TCAM];
        *p_mode = g_drv_ecc_scan_mode[DRV_SER_SCAN_TYPE_TCAM];
    }

    if (DRV_SER_SCAN_TYPE_SBE == type)
    {
        *p_scan_interval = p_drv_ser_master->scan_interval[DRV_SER_SCAN_TYPE_SBE];
        *p_mode = g_drv_ecc_scan_mode[DRV_SER_SCAN_TYPE_SBE];
    }

    return DRV_E_NONE;
}

uint8
drv_ser_get_tcam_scan_enable(uint8 lchip)
{
    drv_ser_master_t* p_drv_ser_master = NULL;

    p_drv_ser_master = (drv_ser_master_t*)(p_drv_master[lchip]->p_ser_master);

    if ((!p_drv_ser_master) || (SDK_WORK_PLATFORM == 1)||(!g_sdb_master[lchip]))
    {
        return 0;
    }

    if(p_drv_ser_master->tcam_scan_en)
    {
        return 1;
    }

    return 0;
}

#define ___ECC_RECOVER_INTERFACE___
/**
 @brief The function get interrupt bits's field id and action type
 @param: mode
            0, lkup intr tbl db by intr_tbl_id and intr_bit
            1, lkup intr tbl db by mem_id and tbl_type
*/
int32
drv_ser_get_intr_info(uint8 lchip, drv_ecc_intr_tbl_t* p_tbl_db_info, uint8 mode)
{
    uint16 tbl_id = 0;
    drv_ecc_intr_tbl_t* p_intr_tbl = NULL;

    DRV_PTR_VALID_CHECK(p_tbl_db_info);

    p_intr_tbl = p_drv_master[lchip]->drv_ecc_data.p_intr_tbl;
    if (!p_intr_tbl)
    {
        return DRV_E_NONE;
    }

    if (mode == 0)
    {
        for (tbl_id = 0; p_intr_tbl[tbl_id].intr_tblid != MaxTblId_t; tbl_id++)
        {
            if ((p_intr_tbl[tbl_id].intr_tblid == p_tbl_db_info->intr_tblid)
                && (p_intr_tbl[tbl_id].intr_bit == p_tbl_db_info->intr_bit))
            {
                p_tbl_db_info->action = p_intr_tbl[tbl_id].action;
                p_tbl_db_info->err_type = p_intr_tbl[tbl_id].err_type;
                p_tbl_db_info->rec_id = p_intr_tbl[tbl_id].rec_id;
                p_tbl_db_info->rec_id_fld = p_intr_tbl[tbl_id].rec_id_fld;
                p_tbl_db_info->mem_id = p_intr_tbl[tbl_id].mem_id;
                p_tbl_db_info->tbl_type = (!g_sdb_master[lchip] || !(p_drv_master[lchip]->p_ser_master))? 0: p_intr_tbl[tbl_id].tbl_type;

                return DRV_E_NONE;
            }
        }

        p_tbl_db_info->action = 0;
        p_tbl_db_info->tbl_type = 0;
        return DRV_E_NONE;
    }
    else
    {
        for (tbl_id = 0; p_intr_tbl[tbl_id].intr_tblid != MaxTblId_t; tbl_id++)
        {
            if ((p_intr_tbl[tbl_id].mem_id == p_tbl_db_info->mem_id) &&
                (p_intr_tbl[tbl_id].tbl_type ==  p_tbl_db_info->tbl_type))
            {
                p_tbl_db_info->intr_tblid  = p_intr_tbl[tbl_id].intr_tblid;
                p_tbl_db_info->intr_fld    = p_intr_tbl[tbl_id].intr_fld;
                return DRV_E_NONE;
            }
        }
        return DRV_E_NONE;
    }
}

#define DRV_TCAM_SCAN_BYTE_PER_UNIT 16
#define DRV_TCAM_SCAN_ENTRY_PER_UNIT 8
#define DRV_TCAM_SCAN_BMP_OFFSET 14
#define DRV_DMA_TCAM_SCAN_CHANNEL 28

#if (SDK_WORK_PLATFORM == 0)

STATIC int32
drv_ser_get_mem_desc_index(uint8 lchip, uint32 mem_id, uint32* p_desc_index)
{
    if (DRV_MCHIP_SER_API(lchip)->ser_get_mem_desc_index)
    {
        DRV_MCHIP_SER_API(lchip)->ser_get_mem_desc_index(lchip, mem_id, p_desc_index);
    }
    return DRV_E_NONE;
}
#endif

uint8 default_entry_hash[] = {0x2A, 0x2A, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B,
0x3B, 0x3B, 0x3B, 0x3B, 0x2A, 0x2A, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x10, 0x3B, 0xA0, 0xCC};
/*
func description:

mem_id : tcam memory id
entry_size : bsaic tcam entry size include data & mask(based on different tcam type:flow/lpm/cid/queue)
start_idx : basic tcam entry start index
end_idx : basic tcam entry end index
entry_num_per_unit : entry num per 16 byte associated with register DmaScanCfg
p_mem_addr : descriptor's data memory address

*/
uint8 _drv_at_ser_get_tcam_default_hash(uint32 mem_id)
{
    uint8 hash = 0;
    switch (mem_id)
    {
    case DRV_FTM_CID_TCAM:
        hash = 0x25;
        break;
    case DRV_FTM_SEL_TCAM:
    case DRV_FTM_SEL_TCAM_EGR:
        hash = 0x43;
        break;
    case DRV_FTM_RMAC_TCAM:
        hash = 0x2A;
        break;
    case DRV_FTM_UDF_TCAM:
        hash = 0x9A;
        break;
    default:
    break;
    }
    if ((mem_id >= DRV_FTM_TCAM_KEY40 && mem_id <= DRV_FTM_TCAM_KEY41)
    || (mem_id >= DRV_FTM_TCAM_KEY0 && mem_id <= DRV_FTM_TCAM_KEY1))
    {
        hash = 0x9A;
    }
    else if (mem_id >= DRV_FTM_TCAM_KEY2 && mem_id <= DRV_FTM_TCAM_KEY39)
    {
        hash = 0x3B;
    }
    else if (mem_id >= DRV_FTM_LPM_TCAM_KEY0 && mem_id <= DRV_FTM_LPM_TCAM_KEYM)
    {
        hash = 0xd1;
    }
    return hash;
}

#if defined(EMULATION_ENV) && !defined(EMULATOR_ENV)
int32
drv_ser_get_entry_hash(uint8 lchip, uint32 mem_id, uint32 entry_size, uint32 start_idx, uint32 end_idx, uint8 entry_num_per_unit, void *p_mem_addr, uint8 is_init, void* test_data)
{
    uint8 *p_mem_temp = NULL;
    //uint8  have_valid_word = 0;
    uint8  loop = 0, word_num = 0;
    uint32 data_src = 0;
    uint32 buf[16] = {0};
    uint32 bmp = 0;
    //uint32 blk_entry_size = 0;
    uint32 entry_idx = 0, entry_num = 0, tmp_entry_size = 0;
    uint32 mem_addr = 0;
//    uint32 entry_valid = 0;
    uint32 desc_index = 0;
    drv_ftm_tcam_info_t tcam_info;
    key_lookup_info_t key_info;
    key_lookup_result_t key_result;
    uint32 crc[3] = {0, 0x0000001D, 8};/* HASH_CRC : x8+x4+x3+x2+1 */

#define DRV_SER_ENTRY_VALID_PER_BYTE    (0x80)
#define DRV_SER_ENTRY_VALID_PER_WORD    (0x80000000)
#define DRV_SER_SIZE_OF_ENTRY_VALID     (4)

    drv_usw_ftm_get_tcam_memory_info(lchip, mem_id, &mem_addr, &entry_num, &tmp_entry_size, &tcam_info);

    DRV_IF_ERROR_RETURN(drv_ser_get_mem_desc_index(lchip, mem_id, &desc_index));
    /*
    p_cpu_addr = p_sdb->dynamic_tbl[mem_id];
    entry_len_aline = drv_sdb_get_tcam_entry_size_aline(lchip, mem_id);
    DRV_IF_ERROR_RETURN(drv_sdb_get_tcam_local_entry_size(lchip, mem_id, &blk_entry_size));
    */
    //have_valid_word = (entry_size>>2)&1;

    //blk_entry_size = (entry_size - (have_valid_word<<2)) >> 1;
    word_num = entry_size>>2;

    key_info.type = crc[0];
    key_info.polynomial = crc[1];
    key_info.poly_len = crc[2];
    key_info.key_data = (uint8*)buf;
    key_info.crc_bits = key_info.key_bits = entry_size<<3;

    for (entry_idx = start_idx; entry_idx < end_idx; entry_idx++)
    {
        /*
        entry_valid = drv_get_field32(lchip, tcam_info.tcam_mem_id, 2, (uint32*)test_data);

        if (!entry_valid)
        {
            key_result.bucket_index = DRV_FROM_AT(lchip) ? _drv_at_ser_get_tcam_default_hash(mem_id) : default_entry_hash[desc_index];
        }
        else
        */
        {
        loop = 0;
        do
        {
            data_src = ((uint32*)test_data)[loop];
            data_src = ((data_src>>1)&0x55555555)|((data_src<<1)&0xaaaaaaaa);
            data_src = ((data_src>>2)&0x33333333)|((data_src<<2)&0xcccccccc);
            data_src = ((data_src>>4)&0x0f0f0f0f)|((data_src<<4)&0xf0f0f0f0);
            data_src = ((data_src>>8)&0x00ff00ff)|((data_src<<8)&0xff00ff00);
            data_src = ((data_src>>16)&0x0000ffff)|((data_src<<16)&0xffff0000);
            buf[word_num - 1 - loop] = data_src;
        }while(++loop < word_num);

        //DRV_SDB_TCAM_DM2XY(&buf[have_valid_word], blk_entry_size);

        _drv_usw_hash_calculate_index(&key_info, &key_result);
        key_result.bucket_index = key_result.bucket_index & 0xFF;
        }

        p_mem_temp = (uint8*)p_mem_addr + (entry_idx / entry_num_per_unit) * DRV_TCAM_SCAN_BYTE_PER_UNIT;/* 16 byte as unit data structure */
		*(p_mem_temp + (entry_idx % entry_num_per_unit)) =  key_result.bucket_index;
        bmp = *((uint16*)(p_mem_temp + DRV_TCAM_SCAN_BMP_OFFSET));
        if(is_init)
        {
            DRV_BMP_SET(&bmp, (entry_idx % entry_num_per_unit));
        }
        *((uint16*)(p_mem_temp + DRV_TCAM_SCAN_BMP_OFFSET)) = bmp;
    }

    return DRV_E_NONE;
}
#else
int32
drv_ser_get_entry_hash(uint8 lchip, uint32 mem_id, uint32 entry_idx, uint8* p_hash_value)
{
#if (SDK_WORK_PLATFORM == 0)
    uint8 *p_cpu_addr = NULL;
    uint8  have_valid_word = 0;
    uint8  loop = 0, word_num = 0;
    uint32 data_src = 0;
    uint32 buf[16] = {0};
    uint32 blk_entry_size = 0;
    uint32 entry_num = 0, entry_size = 0;
    uint32 mem_addr = 0;
    uint32 entry_valid = 0;
    uint32 desc_index = 0;
    drv_ftm_tcam_info_t tcam_info;
    key_lookup_info_t key_info;
    key_lookup_result_t key_result;
    uint32 crc[3] = {0, 0x0000001D, 8};/* HASH_CRC : x8+x4+x3+x2+1 */

#define DRV_SER_ENTRY_VALID_PER_BYTE    (0x80)
#define DRV_SER_ENTRY_VALID_PER_WORD    (0x80000000)
#define DRV_SER_SIZE_OF_ENTRY_VALID     (4)

    if (!g_sdb_master[lchip] || SDB_DIS == p_drv_master[lchip]->sdb_type||0 == DRV_SDB_DB(lchip)->sdb_en)
    {
        return DRV_E_NONE;
    }

    sal_memset(&key_result, 0, sizeof(key_lookup_result_t));

    drv_usw_ftm_get_tcam_memory_info(lchip, mem_id, &mem_addr, &entry_num, &entry_size, &tcam_info);
    have_valid_word = (entry_size>>2)&1;
    p_cpu_addr = (uint8*)tcam_info.sw_addr;
    blk_entry_size = (entry_size - (have_valid_word<<2)) >> 1;
    word_num = entry_size>>2;

    key_info.type = crc[0];
    key_info.polynomial = crc[1];
    key_info.poly_len = crc[2];
    key_info.key_data = (uint8*)buf;
    key_info.crc_bits = key_info.key_bits = entry_size<<3;

    entry_valid = drv_get_field32(lchip, tcam_info.tcam_mem_id, 2, (uint32*)(p_cpu_addr + entry_idx * tcam_info.entry_offset));
    if (!entry_valid)
    {
        if (p_drv_master[lchip]->dev_type >= DRV_ARCTIC)
        {
            key_result.bucket_index = _drv_at_ser_get_tcam_default_hash(mem_id);
        }
        else
        {
            DRV_IF_ERROR_RETURN(drv_ser_get_mem_desc_index(lchip, mem_id, &desc_index));
            key_result.bucket_index = default_entry_hash[desc_index];
        }
    }
    else
    {
        loop = 0;
        do
        {
            data_src = ((uint32*)(p_cpu_addr + entry_idx * tcam_info.entry_offset))[loop];
            data_src = ((data_src>>1)&0x55555555)|((data_src<<1)&0xaaaaaaaa);
            data_src = ((data_src>>2)&0x33333333)|((data_src<<2)&0xcccccccc);
            data_src = ((data_src>>4)&0x0f0f0f0f)|((data_src<<4)&0xf0f0f0f0);
            data_src = ((data_src>>8)&0x00ff00ff)|((data_src<<8)&0xff00ff00);
            data_src = ((data_src>>16)&0x0000ffff)|((data_src<<16)&0xffff0000);
            buf[word_num - 1 - loop] = data_src;
        }while(++loop < word_num);

        DRV_SDB_TCAM_DM2XY(&buf[have_valid_word], blk_entry_size);
        _drv_usw_hash_calculate_index(&key_info, &key_result);
    }
    *p_hash_value = (uint8)(key_result.bucket_index&0xFF);
#endif

    return DRV_E_NONE;
}
int32
drv_ser_set_entry_hash(uint8 lchip, uint32 entry_idx, uint8 hash_value, void *p_mem_addr, uint8 is_init)
{
#if (SDK_WORK_PLATFORM == 0)
    uint8 *p_mem_temp = NULL;
    uint32 bmp = 0;

    if (!g_sdb_master[lchip] || SDB_DIS == p_drv_master[lchip]->sdb_type||0 == DRV_SDB_DB(lchip)->sdb_en)
    {
        return DRV_E_NONE;
    }

    /* update dma memory hash value */
    p_mem_temp = (uint8*)p_mem_addr + (entry_idx / DRV_TCAM_SCAN_ENTRY_PER_UNIT) * DRV_TCAM_SCAN_BYTE_PER_UNIT;/* 16 byte as unit data structure */
    *(p_mem_temp + (entry_idx % DRV_TCAM_SCAN_ENTRY_PER_UNIT)) =  hash_value;
    /* init update hash num per desc */
    if(is_init)
    {
        bmp = *((uint16*)(p_mem_temp + DRV_TCAM_SCAN_BMP_OFFSET));
        DRV_BIT_SET(bmp, (entry_idx % DRV_TCAM_SCAN_ENTRY_PER_UNIT));
        *((uint16*)(p_mem_temp + DRV_TCAM_SCAN_BMP_OFFSET)) = bmp;
    }
#endif

    return DRV_E_NONE;
}
#endif

int32
drv_ser_get_global_index(uint8 lchip, uint32 mem_id, uint32 local_index, uint32 *entry_index)
{
    if (DRV_FTM_TCAM_KEY0 <= mem_id && mem_id <= DRV_FTM_TCAM_KEY1)
    {
        *entry_index = local_index + ((mem_id - DRV_FTM_TCAM_KEY0) << 9);
    }
    else if (DRV_FTM_TCAM_KEY2 <= mem_id && mem_id <= DRV_FTM_TCAM_KEY3)
    {
        *entry_index = local_index + ((mem_id - DRV_FTM_TCAM_KEY2) << 10);
    }
    else if (DRV_FTM_TCAM_KEY4 <= mem_id && mem_id <= DRV_FTM_TCAM_KEY19)
    {
        *entry_index = local_index + ((mem_id - DRV_FTM_TCAM_KEY4) << 11);
    }
    else if (DRV_FTM_TCAM_KEY20 <= mem_id && mem_id <= DRV_FTM_TCAM_KEY23)
    {
        *entry_index = local_index + ((mem_id - DRV_FTM_TCAM_KEY20) << 10);
    }
    else if (DRV_FTM_TCAM_KEY24 <= mem_id && mem_id <= DRV_FTM_TCAM_KEY25)
    {
        *entry_index = local_index + ((mem_id - DRV_FTM_TCAM_KEY24) << 8);
    }
    else if (DRV_FTM_LPM_TCAM_KEY0 <= mem_id && mem_id <= DRV_FTM_LPM_TCAM_KEY1)
    {
        *entry_index = local_index + ((mem_id - DRV_FTM_LPM_TCAM_KEY0) << 12);
    }
    else if (DRV_FTM_LPM_TCAM_KEY2 <= mem_id && mem_id <= DRV_FTM_LPM_TCAM_KEY3)
    {
        *entry_index = local_index + ((mem_id - DRV_FTM_LPM_TCAM_KEY2) << 12) + 16 * 1024;
    }
    else if (DRV_FTM_LPM_TCAM_KEY4 <= mem_id && mem_id <= DRV_FTM_LPM_TCAM_KEY5)
    {
        *entry_index = local_index + ((mem_id - DRV_FTM_LPM_TCAM_KEY4) << 13) + 32 * 1024;
    }
    else
    {
        /* ltid & udf & routermac & cid */
        *entry_index = local_index;
    }

    return DRV_E_NONE;
}

int32
drv_ser_get_tcam_memory_info_from_error_addr(uint8 lchip, uint32 error_addr, uint32* mem_id, uint32* entry_index, uint32* tcam_mem_id)
{
#define DRV_TCAM_NUM    36

    uint32 mem_addr = 0;
    uint32 tbl_id = 0;
    uint32 local_index = 0;
    uint8  tcam_index = DRV_TCAM_NUM >> 1;
    uint8  start_index = 0, end_index = DRV_TCAM_NUM-1;
    int8   error_addr_dir = 0;
    static uint16 mem_id_in_order[DRV_TCAM_NUM] = {
        DRV_FTM_TCAM_KEY24,     DRV_FTM_TCAM_KEY25,
        DRV_FTM_LPM_TCAM_KEY0,  DRV_FTM_LPM_TCAM_KEY1,
        DRV_FTM_LPM_TCAM_KEY2,  DRV_FTM_LPM_TCAM_KEY3,
        DRV_FTM_LPM_TCAM_KEY4,  DRV_FTM_LPM_TCAM_KEY5,
        DRV_FTM_TCAM_KEY4,      DRV_FTM_TCAM_KEY5,
        DRV_FTM_TCAM_KEY6,      DRV_FTM_TCAM_KEY7,
        DRV_FTM_TCAM_KEY8,      DRV_FTM_TCAM_KEY9,
        DRV_FTM_TCAM_KEY10,     DRV_FTM_TCAM_KEY11,
        DRV_FTM_TCAM_KEY12,     DRV_FTM_TCAM_KEY13,
        DRV_FTM_TCAM_KEY14,     DRV_FTM_TCAM_KEY15,
        DRV_FTM_TCAM_KEY16,     DRV_FTM_TCAM_KEY17,
        DRV_FTM_TCAM_KEY18,     DRV_FTM_TCAM_KEY19,
        DRV_FTM_CID_TCAM,       DRV_FTM_TCAM_KEY2,
        DRV_FTM_TCAM_KEY3,      DRV_FTM_TCAM_KEY0,
        DRV_FTM_TCAM_KEY1,      DRV_FTM_RMAC_TCAM,
        DRV_FTM_UDF_TCAM,       DRV_FTM_SEL_TCAM,
        DRV_FTM_TCAM_KEY20,     DRV_FTM_TCAM_KEY21,
        DRV_FTM_TCAM_KEY22,     DRV_FTM_TCAM_KEY23};

    mem_addr = DRV_MEM_ADD0(lchip, mem_id_in_order[tcam_index]);
    error_addr_dir = error_addr < mem_addr? -1: error_addr_dir;
    error_addr_dir = error_addr >= DRV_MEM_ADD0(lchip, mem_id_in_order[tcam_index+1])? 1: error_addr_dir;
    while(error_addr_dir != 0)
    {
        if (error_addr_dir > 0)
        {
            start_index = tcam_index + 1;
        }
        else
        {
            end_index = tcam_index - 1;
        }
        tcam_index = (start_index + end_index) >> 1;
        mem_addr = DRV_MEM_ADD0(lchip, mem_id_in_order[tcam_index]);
        error_addr_dir = error_addr < mem_addr? -1: 0;
        error_addr_dir = (tcam_index < (DRV_TCAM_NUM-1)) && error_addr >= DRV_MEM_ADD0(lchip, mem_id_in_order[tcam_index+1])? 1: error_addr_dir;
    }
    tbl_id = DRV_TCAM_MAP(lchip, DRV_MEM_TCAM_ID(lchip, mem_id_in_order[tcam_index]));
    *mem_id = mem_id_in_order[tcam_index];
    local_index = (error_addr - mem_addr) / TABLE_ENTRY_OFFSET(lchip, tbl_id);
    drv_ser_get_global_index(lchip, *mem_id, local_index, entry_index);
    *tcam_mem_id = tbl_id;

    return DRV_E_NONE;
}

/**
 @brief The function compare cached tcam data/mask with data/mask read from hw,
        if compare failed, recover from cached data/mask and send tcam error event log.
*/
int32
drv_ser_dma_recover_tcam(uint8 lchip, drv_ser_dma_tcam_param_t* p_param)
{
    uint32 entry_num = 0;
    uint32* time_stamp = NULL;
    uint32* p_memory = NULL;
    uint32  mem_id = 0;
    uint8  entry_size_per_index = 0;
    uint32 entry_idx = 0, mem_offset = 0;
    uint32 entry_size = 0;
    uint32 hw_addr = 0;
    uint32* p_data_buffer = NULL;
    uint32* p_hw_buffer = NULL;
    uint32* p_sw_buffer = NULL;
    drv_ser_cb_info_t  ser_cb_info;
    drv_ftm_tcam_info_t tcam_info;
    drv_ser_master_t* p_drv_ser_master = (drv_ser_master_t*)(p_drv_master[lchip]->p_ser_master);
    drv_sdb_t* p_sdb = g_sdb_master[lchip];

    if ((0 == drv_ser_get_tcam_scan_enable(lchip)) || (p_sdb == NULL) || (p_drv_ser_master == NULL))
    {
#if defined(EMULATION_ENV) && !defined(EMULATOR_ENV)
#else
        return DRV_E_NONE;
#endif
    }
    if(!p_param)
    {
        return DRV_E_INVALID_POINT;
    }

    if (DRV_MCHIP_SER_API(lchip) && DRV_MCHIP_SER_API(lchip)->ser_dma_recover_tcam)
    {
        DRV_MCHIP_SER_API(lchip)->ser_dma_recover_tcam(lchip, p_param);
        return DRV_E_NONE;
    }

    mem_id = p_param->mem_id;
    time_stamp = p_param->time_stamp;
    p_memory = p_param->p_memory;

    if((time_stamp[1] <= p_sdb->dma_scan_timestamp[mem_id][1]) || \
        ((time_stamp[1] == p_sdb->dma_scan_timestamp[mem_id][1]) && (time_stamp[0]-DRV_SER_GRANULARITY) <= p_sdb->dma_scan_timestamp[mem_id][0]))
    {
        return 0;
    }

    drv_usw_ftm_get_tcam_memory_info(lchip, mem_id, &hw_addr, &entry_num, &entry_size, &tcam_info);
    entry_size_per_index = (entry_size >> 3) << 2;

    /*alloc memory*/
    p_data_buffer = mem_malloc(MEM_SYSTEM_MODULE, tcam_info.entry_offset*entry_num);
    if (NULL ==  p_data_buffer)
    {
        DRV_DBG_INFO("DRV_SDB:No Memory.\n");
        return DRV_E_NO_MEMORY;
    }
    sal_memcpy(p_data_buffer, p_memory, tcam_info.entry_offset*entry_num);

    /*compare sw and hw data memory, if error recover hw*/
    entry_idx = 0;
    do
    {
        mem_offset = entry_idx * tcam_info.entry_offset;
        p_hw_buffer = (uint32*)((uint8*)p_data_buffer + mem_offset);
        p_sw_buffer = (uint32*)(tcam_info.sw_addr+mem_offset);
        DRV_SDB_TCAM_XY2DM(p_hw_buffer, entry_size_per_index);
        if (!DRV_IS_BIT_SET(p_sw_buffer[(entry_size>>2)-1], 31) || 0 == sal_memcmp((uint8*)p_hw_buffer, (uint8*)p_sw_buffer, entry_size))
        {
            continue;
        }
        DRV_SER_BUFFER_DUMP("hw buffer: ", p_hw_buffer, entry_size);
        DRV_SER_BUFFER_DUMP("sw buffer: ", p_sw_buffer, entry_size);

        drv_usw_chip_write_sram_entry(lchip, hw_addr+mem_offset, p_sw_buffer, entry_size);
        drv_usw_chip_read_sram_entry(lchip, hw_addr+mem_offset, p_hw_buffer, entry_size);
        DRV_SDB_TCAM_XY2DM(p_hw_buffer, entry_size_per_index);
        ser_cb_info.type = DRV_SER_TYPE_TCAM_ERROR;
        ser_cb_info.tbl_id = 0xFE000000 + mem_id;
        ser_cb_info.tbl_index =  entry_size*entry_idx;
        ser_cb_info.tbl_id |= entry_size << 18;
        ser_cb_info.recover = (sal_memcmp((uint8*)p_hw_buffer, (uint8*)p_sw_buffer, entry_size)? 2 :1);
        ser_cb_info.action = DRV_SER_ACTION_LOG;
        ser_cb_info.intr_type = NULL;
        drv_ser_report_ser_event_cb(lchip, &ser_cb_info);
        (p_drv_ser_master->recover_tcam_key)++;
    }while(++entry_idx < entry_num);

    mem_free(p_data_buffer);
    return DRV_E_NONE;
}

/**
 @brief The function recover the ecc error memory with handle info
*/
int32
drv_ser_restore(uint8 lchip, drv_ecc_intr_param_t* p_intr_param)
{
    uint8 intr_bit = 0;
    uint8 valid_cnt = 0;
    drv_ser_cb_info_t  ser_cb_info;
    drv_ser_master_t* p_drv_ser_master = NULL;
    drv_ecc_intr_tbl_t table_info_intr;
    uint8 ecc_tbl_type = 0;
    DRV_PTR_VALID_CHECK(p_intr_param);

    p_drv_ser_master = (drv_ser_master_t*)(p_drv_master[lchip]->p_ser_master);

    if ((!g_sdb_master[lchip]) || (SDB_DIS == (p_drv_master[lchip]->sdb_type)) || (0 == DRV_SDB_DB(lchip)->sdb_en) ||
        (!p_drv_ser_master) || (!p_drv_ser_master->ecc_recover_en))
    {
        return DRV_E_NONE;
    }

    for (intr_bit = 0; (valid_cnt < p_intr_param->valid_bit_count) && (intr_bit < p_intr_param->total_bit_num); intr_bit++)
    {
        if (!DRV_BMP_ISSET(p_intr_param->p_bmp, intr_bit))
        {
            continue;
        }

        /*get intr db info*/
        table_info_intr.intr_tblid = p_intr_param->intr_tblid;
        table_info_intr.intr_bit = intr_bit;
        DRV_IF_ERROR_RETURN(drv_ser_get_intr_info(lchip, &table_info_intr, 0));
        ecc_tbl_type = table_info_intr.tbl_type;

        if (!table_info_intr.rec_id)
        {
            (p_drv_ser_master->ignore_cnt)++;
            ser_cb_info.recover    = 0;
            ser_cb_info.tbl_id     = table_info_intr.mem_id;  /* get intr tbl by intr_type */
            ser_cb_info.tbl_index  = 0xFFFFFFFF;
            ser_cb_info.type       = table_info_intr.err_type;
            ser_cb_info.action     = table_info_intr.action;
        }
        else if (ecc_tbl_type == DRV_ECC_TBL_TYPE_STATIC)
        {
            DRV_IF_ERROR_RETURN(_drv_ser_restore_static_tbl(lchip, &table_info_intr, &ser_cb_info));
        }
        else if ((ecc_tbl_type == DRV_ECC_TBL_TYPE_HASH_KEY) || (ecc_tbl_type == DRV_ECC_TBL_TYPE_DYNAMIC_SRAM))
        {
            DRV_IF_ERROR_RETURN(_drv_ecc_restore_dynamic_sram(lchip , &table_info_intr ,&ser_cb_info));
        }
        else
        {
             /*DRV_DBG_INFO("[DRV_ECC]:unknown table[tblid:%d,fld:%d] ,can't do ecc recover\n",p_intr_param->intr_tblid,intr_bit);*/
            return DRV_E_NONE;
        }

        valid_cnt++;
        ser_cb_info.intr_type = p_intr_param->intr_type;
        drv_ser_report_ser_event_cb(lchip, &ser_cb_info);


    }
    return DRV_E_NONE;
}

#if defined(EMULATION_ENV) && !defined(EMULATOR_ENV)
inline int32
drv_ser_set_entry_bitmap(uint8 lchip, uint32 mem_id, uint32 entry_idx, uint8 enable, uint8 need_cal_hash, void* test_data)
{
    uint8 entry_num_per_unit = 0;
    uint32 desc_idx = 0;
    uint32 cfg_size = 0;
    uint32 *p_desc_addr = NULL;
    uint32 *p_mem_addr = NULL;
    uint32 entry_num = 0;
    uint32 entry_size = 0;
    uint32 mem_addr = 0;
    drv_sdb_t* p_sdb = g_sdb_master[drv_vchip_get_pp_base(lchip)];

    /*lpm mem_id mapping*/
    if (mem_id == DRV_FTM_LPM_TCAM_KEY0)
    {
        mem_id = DRV_FTM_LPM_TCAM_KEY0 + (entry_idx >> 12);
        entry_idx %= 4096;
    }
    else if (mem_id == DRV_FTM_LPM_TCAM_KEY1)
    {
        mem_id = DRV_FTM_LPM_TCAM_KEY2 + (entry_idx >> 12);
        entry_idx %= 4096;
    }
    else if (mem_id == DRV_FTM_LPM_TCAM_KEY4 + 2)
    {
        mem_id = mem_id + (entry_idx >> 13) - 2;
        entry_idx %= 8192;
    }

    /* step1 : get the memory id corresponding descriptor */
    DRV_IF_ERROR_RETURN(drv_ser_get_mem_desc_index(lchip, mem_id, &desc_idx));
    desc_idx += 1;

    /* step2 : get descriptor info */
    if (p_sdb->get_dma_data_memory_cb)
    {
        p_sdb->get_dma_data_memory_cb(lchip, DRV_DMA_TCAM_SCAN_CHANNEL, desc_idx, mem_id, &cfg_size, &p_desc_addr, &p_mem_addr);
    }

    if (!p_desc_addr)
    {
        return DRV_E_NONE;
    }
    //sys_usw_dma_get_tcam_scan_entry_num_cfg(lchip, &entry_num_per_unit);
    entry_num_per_unit = DRV_TCAM_SCAN_ENTRY_PER_UNIT;
    drv_usw_ftm_get_tcam_memory_info(lchip, mem_id, &mem_addr, &entry_num, &entry_size, NULL);

    /* step3 set bmp */
#if 0
    p_mem_temp = (uint8*)p_mem_addr + (entry_idx / entry_num_per_unit) * DRV_TCAM_SCAN_BYTE_PER_UNIT;/* 16 byte as unit data structure */
    bmp = *((uint16*)(p_mem_temp + DRV_TCAM_SCAN_BMP_OFFSET));
    enable ? DRV_BMP_SET(&bmp, (entry_idx % entry_num_per_unit)) : DRV_BMP_UNSET(&bmp, (entry_idx % entry_num_per_unit));
    *((uint16*)(p_mem_temp + DRV_TCAM_SCAN_BMP_OFFSET)) = bmp;
#endif

    /* step4 re-calculate entry hash */
    if (need_cal_hash)
    {
        drv_ser_get_entry_hash(lchip, mem_id, entry_size, entry_idx, entry_idx + 1, entry_num_per_unit, p_mem_addr, 0, test_data);
    }

    return DRV_E_NONE;
}

#else
inline int32
drv_ser_set_entry_bitmap(uint8 lchip, uint32 mem_id, uint32 entry_idx, uint8 oper_bmp)
{
#if (SDK_WORK_PLATFORM == 0)
    //uint8 *p_mem_temp = NULL;
    //uint32 bmp = 0;
    uint32 desc_idx = 0;
    uint32 cfg_size = 0;
    uint32 *p_desc_addr = NULL;
    uint32 *p_mem_addr = NULL;
    drv_sdb_t* p_sdb = g_sdb_master[drv_vchip_get_pp_base(lchip)];
    uint8 pp_id = 0;
    uint8 hash_value = 0;
    uint8 core_id = 0;
    uint8 core_pp_base = 0;
    uint8 core_num = ((DRV_TSINGMA_MX == p_drv_master[lchip]->dev_type)? 1: 2);

    /*lpm mem_id mapping*/
    if (mem_id == DRV_FTM_LPM_TCAM_KEY0)
    {
        mem_id = DRV_FTM_LPM_TCAM_KEY0 + (entry_idx >> 12);
        entry_idx %= 4096;
    }
    else if (mem_id == DRV_FTM_LPM_TCAM_KEY1)
    {
        mem_id = DRV_FTM_LPM_TCAM_KEY2 + (entry_idx >> 12);
        entry_idx %= 4096;
    }
    else if (mem_id == DRV_FTM_LPM_TCAM_KEY2)
    {
        mem_id = DRV_FTM_LPM_TCAM_KEY4 + (entry_idx >> 13);
        entry_idx %= 8192;
    }
    else if (mem_id == DRV_FTM_LPM_TCAM_KEY4 + 2)
    {/*process NAT tcam*/
        mem_id = mem_id + (entry_idx >> 13) - 2;
        entry_idx %= 8192;
    }
    /* step1 : get the memory id corresponding descriptor */
    DRV_IF_ERROR_RETURN(drv_ser_get_mem_desc_index(lchip, mem_id, &desc_idx));
    desc_idx += 1;
    /* step2 : re-calculate entry hash */
    drv_ser_get_entry_hash(lchip, mem_id, entry_idx, &hash_value);
    /* step3 : update entry hash */
    for (core_id = 0; core_id < core_num; core_id++)
    {
        if (!DRV_IS_BIT_SET(oper_bmp, (6+core_id)) && (DRV_ARCTIC == p_drv_master[lchip]->dev_type))
        {
            continue;
        }
        core_pp_base = (core_id >= 1) ? drv_vchip_get_pp_base(lchip) + p_drv_master[lchip]->core_pp_num : drv_vchip_get_pp_base(lchip);
        for (pp_id = 0; pp_id < p_drv_master[lchip]->core_pp_num; pp_id++)
        {
            if (!DRV_IS_BIT_SET(oper_bmp, pp_id + 2) && (DRV_ARCTIC == p_drv_master[lchip]->dev_type)) 
            { 
                continue; 
            }
            if (p_sdb->get_dma_data_memory_cb)
            {
                p_sdb->get_dma_data_memory_cb(core_pp_base, DRV_DMA_TCAM_SCAN_CHANNEL, desc_idx+53*pp_id, mem_id, &cfg_size, &p_desc_addr, &p_mem_addr);
            }
            if (!p_desc_addr)
            {
                return DRV_E_NONE;
            }
            drv_ser_set_entry_hash(lchip, entry_idx, hash_value, p_mem_addr, 0);
        }
    }
#endif
    return DRV_E_NONE;
}
#endif



#define ___ECC_RECOVER_CFG___

/**
 @brief Set scan burst interval entry num and time(ms)
*/
int32
drv_ser_set_tcam_scan_cfg(uint8 lchip,uint32 burst_entry_num, uint32 burst_interval)
{
    drv_ser_master_t* p_ser_master = NULL;

    if (p_drv_master[lchip]->dev_type >= DRV_TSINGMA_MX)
    {
        return DRV_E_INVALID_PARAMETER;
    }

    p_ser_master = (drv_ser_master_t*)(p_drv_master[lchip]->p_ser_master);
    if (p_ser_master == NULL)
    {
        return DRV_E_FATAL_EXCEP;
    }

    if (burst_interval && (0 == burst_entry_num))
    {
        return DRV_E_INVALID_PARAMETER;
    }

    p_ser_master->tcam_scan_burst_entry_num = burst_interval ? burst_entry_num : 0xFFFFFFFF;
    p_ser_master->tcam_scan_burst_interval = burst_interval;

    return DRV_E_NONE;
}

/**
 @brief The function simulate ecc error-tbl/sram'index/offset
 @mode : 0-disable, 1-enable
*/
int32
drv_ser_set_ecc_simulation_idx(uint8 lchip, uint8 mode, uint32 tbl_idx)
{
    drv_ser_master_t* p_drv_ser_master = NULL;

    p_drv_ser_master = (drv_ser_master_t*)(p_drv_master[lchip]->p_ser_master);
    if (!p_drv_ser_master)
    {
        return DRV_E_NONE;

    }
    else
    {
        p_drv_ser_master->err_rec_offset = tbl_idx;
        p_drv_ser_master->simulation_en = mode;
    }
    return DRV_E_NONE;
}


#define ___ECC_RECOVER_STATS___
int32
drv_ser_show_status(uint8 lchip)
{
    char str[32] = {0};
    drv_ser_master_t* p_drv_ser_master = NULL;
    uint32   static_catch_mem_size   = 0;
    uint32   dynamic_catch_mem_size  = 0;
    uint32   tcam_key_catch_mem_size = 0;
    uint32   ecc_catch_mem_size      = 0;
    drv_sdb_t* p_sdb = NULL;

    if (!g_sdb_master[lchip] || !p_drv_master[lchip])
    {
        return DRV_E_NONE;
    }
    p_sdb = g_sdb_master[lchip];

    p_drv_ser_master = (drv_ser_master_t*)(p_drv_master[lchip]->p_ser_master);
    if (!p_drv_ser_master)
    {
        DRV_DUMP_INFO("SER NOT enable.\n");
        return DRV_E_NONE;
    }

    static_catch_mem_size = p_sdb->catch_mem_static_size;
    dynamic_catch_mem_size = p_sdb->catch_mem_dynamic_size;
    tcam_key_catch_mem_size = p_sdb->catch_mem_tcam_key_size;
    ecc_catch_mem_size = static_catch_mem_size + dynamic_catch_mem_size;

    DRV_DUMP_INFO("\n");

    /*multibit/parity*/
    if  (0 == ecc_catch_mem_size)
    {
        sal_sprintf(str, "%s", "0");
    }
    else
    {
        sal_sprintf(str, "%u", ecc_catch_mem_size/1024);
    }
    DRV_DUMP_INFO(" %-23s%-10s\n", "EccMultiBit/Parity:",(p_drv_ser_master->ecc_recover_en ? "Yes" : "No"));
    DRV_DUMP_INFO(" %-23s%-10s\n", "--Memory Size(kb)", str);
    DRV_DUMP_INFO("\n");

    /*tcam key scan*/
    if (0 == tcam_key_catch_mem_size)
    {
        sal_sprintf(str, "%s", "0");
    }
    else
    {
        sal_sprintf(str, "%u", tcam_key_catch_mem_size/1024);
    }
    DRV_DUMP_INFO(" %-23s%-10s\n", "TcamScan:",(p_drv_ser_master->tcam_scan_en ? "Yes" : "No"));
    DRV_DUMP_INFO(" %-23s%-10s\n", "--Memory Size(kb)", str);
    DRV_DUMP_INFO(" %-23s%-10d\n", "--Scan mode", g_drv_ecc_scan_mode[DRV_SER_SCAN_TYPE_TCAM]);
    DRV_DUMP_INFO(" %-23s%-10d\n", "--Scan interval(minute)", p_drv_ser_master->scan_interval[DRV_SER_SCAN_TYPE_TCAM]);
    DRV_DUMP_INFO(" %-23s%-10s\n", "--Scan doing",(p_drv_ser_master->scan_doing[DRV_SER_SCAN_TYPE_TCAM]?"Yes":"No"));
    DRV_DUMP_INFO("\n");

    /*sbe scan*/
    DRV_DUMP_INFO(" %-23s%-10s\n", "SingleBitScan:",(p_drv_ser_master->tcam_scan_en ? "Yes" : "No"));
    DRV_DUMP_INFO(" %-23s%-10d\n", "--Scan mode", g_drv_ecc_scan_mode[DRV_SER_SCAN_TYPE_SBE]);
    DRV_DUMP_INFO(" %-23s%-10d\n", "--Scan interval(minute)", p_drv_ser_master->scan_interval[DRV_SER_SCAN_TYPE_SBE]);
    DRV_DUMP_INFO(" %-23s%-10s\n", "--Scan doing",(p_drv_ser_master->scan_doing[DRV_SER_SCAN_TYPE_SBE]?"Yes":"No"));

    /***************************recover cnt status************************/
    DRV_DUMP_INFO(" --------------------------------------------\n\n");
    DRV_DUMP_INFO(" %-33s%s\n", "RecoverMemory", "RestoreCount");
    DRV_DUMP_INFO(" ---------------------------------------------\n");
    /*static tbl*/
    if (p_drv_ser_master->recover_static_cnt)
    {
        sal_memset(&str, 0, sizeof(str));
        sal_sprintf(str, "%s","static_table:");
        DRV_DUMP_INFO(" %-33s%u\n", str, p_drv_ser_master->recover_static_cnt);
    }
    /*dynamic tbl*/
    if (p_drv_ser_master->recover_dynamic_cnt)
    {
        sal_memset(&str, 0, sizeof(str));
        sal_sprintf(str, "%s","dynamic_table:");
        DRV_DUMP_INFO(" %-33s%u\n", str, p_drv_ser_master->recover_dynamic_cnt);
    }
    /*tcam key*/
    if (p_drv_ser_master->recover_tcam_key)
    {
        sal_memset(&str, 0, sizeof(str));
        sal_sprintf(str, "%s","tcam_key:");
        DRV_DUMP_INFO(" %-33s%u\n", str, p_drv_ser_master->recover_tcam_key);
    }
    /*single bit error*/
    if (p_drv_ser_master->recover_sbe_cnt)
    {
        sal_memset(&str, 0, sizeof(str));
        sal_sprintf(str, "%s","single bit:");
        DRV_DUMP_INFO(" %-33s%u\n", str, p_drv_ser_master->recover_sbe_cnt);
    }

    /******************************ignore cnt status**********************/
    if (p_drv_ser_master->ignore_cnt)
    {
        DRV_DUMP_INFO("\n");
        DRV_DUMP_INFO(" ---------------------------------------------\n");
        DRV_DUMP_INFO(" %-33s%u\n","Ignore count", p_drv_ser_master->ignore_cnt);
    }

    if (p_sdb->mem_size)
    {
        DRV_DUMP_INFO("\n");
        DRV_DUMP_INFO(" ---------------------------------------------\n");
        DRV_DUMP_INFO(" %-27s%-10d\n", "SER DB Memory Total(kb)",(p_sdb->mem_size)/1024);
        DRV_DUMP_INFO(" %-27s%-10d\n", "--Used Memory Size(kb)",(drv_sdb_calc_tbl_size(lchip, 2) + 1023)>>10);
        DRV_DUMP_INFO(" %-27s%-10d\n", "--Reserve Memory Size(kb)", (p_sdb->mem_size - drv_sdb_calc_tbl_size(lchip, 2) + 1023)>>10);
    }
    return DRV_E_NONE;
}


#define ___ECC_RECOVER_INIT___

int32
drv_ser_mem_check(uint8 lchip, uint8 mem_id, uint8 recover_en, uint8* cmp_result)
{
    drv_sdb_t* p_sdb = NULL;

    p_sdb = g_sdb_master[lchip];
    if (NULL == p_sdb)
    {
        return DRV_E_NONE;
    }
    DRV_IF_ERROR_RETURN(drv_sdb_check_per_ram(lchip, mem_id, recover_en, cmp_result, NULL));
    return DRV_E_NONE;
}

void
drv_ser_get_master_info(uint8 lchip, uint8* ecc_recover_en)
{
    drv_ser_master_t* p_drv_ser_master = p_drv_master[lchip]->p_ser_master;
    if (p_drv_ser_master)
    {
        *ecc_recover_en = p_drv_ser_master->ecc_recover_en;
    }
}

int32
drv_ser_init(uint8 lchip , drv_ser_global_cfg_t* p_cfg)
{
    drv_ser_master_t* p_drv_ser_master = NULL;
    int32 ret = 0;
    drv_ecc_sbe_cnt_t*  p_sbe_cnt = NULL;
    uint32 data[32] = {0};
    uint32 value = 0;
    uint32 index = 0;
    uint32 cmd = 0;

    DRV_PTR_VALID_CHECK(p_cfg);

#if (SDB_MEM_MODEL == SDB_MODE)
    return DRV_E_NONE;
#endif

#if defined(EMULATION_ENV) && !defined(EMULATOR_ENV)
#else
    if ((SDK_WORK_PLATFORM == 1) \
        || ( p_drv_master[lchip]->p_ser_master) \
        || (NULL == g_sdb_master[lchip]) || (p_cfg->sdb_type != SDB_ALL) \
        || ((0 == p_cfg->ecc_recover_en) && (0 == p_cfg->tcam_scan_en) && (0 == p_cfg->sbe_scan_en)))
    {
        return DRV_E_NONE;
    }
#endif
    p_drv_ser_master = (drv_ser_master_t*)mem_malloc(MEM_SYSTEM_MODULE, sizeof(drv_ser_master_t));
    p_drv_master[lchip]->p_ser_master = p_drv_ser_master;
    if (!p_drv_ser_master)
    {
        return DRV_E_NO_MEMORY;
    }
    sal_memset(p_drv_ser_master, 0, sizeof(drv_ser_master_t));

    p_sbe_cnt = p_drv_master[lchip]->drv_ecc_data.p_sbe_cnt;
    /* CTC_WB_STATUS_RELOADING: 2 */
    if (2 == p_drv_master[lchip]->wb_status)
    {
        for (index = 0; (MaxTblId_t != p_sbe_cnt[index].rec); index++)
        {
            cmd = DRV_IOR(p_sbe_cnt[index].rec, DRV_ENTRY_FLAG);
            ret = (DRV_IOCTL(lchip, p_sbe_cnt[index].index, cmd, data));
            if (ret)
            {
                continue;
            }
            DRV_GET_FIELD(lchip,p_sbe_cnt[index].rec, p_sbe_cnt[index].fld, data, &value);
            p_sbe_cnt[index].old_value = value;
        }
    }

    p_drv_ser_master->ecc_recover_en = p_cfg->ecc_recover_en;
    p_drv_ser_master->tcam_scan_en = p_cfg->tcam_scan_en;
    p_drv_ser_master->sbe_scan_en = p_cfg->sbe_scan_en;
    p_drv_ser_master->scan_interval[DRV_SER_SCAN_TYPE_SBE] = 0;
    p_drv_ser_master->scan_interval[DRV_SER_SCAN_TYPE_TCAM] = ((p_drv_master[lchip]->dev_type >= DRV_TSINGMA_MX) ? 60 : 0);
    p_drv_ser_master->tcam_scan_burst_interval = 5 * 1000;
    p_drv_ser_master->tcam_scan_burst_entry_num = (0 == p_cfg->tcam_scan_burst_entry_num)
    ? 4096 : p_cfg->tcam_scan_burst_entry_num;

    /*step1: scan task create*/
    if ((p_drv_ser_master->sbe_scan_en) && (p_cfg->sbe_scan_interval))
    {
        ret = drv_ser_set_mem_scan_mode(lchip, DRV_SER_SCAN_TYPE_SBE,
                                                     (p_cfg->sbe_scan_interval != 0),
                                                     p_cfg->sbe_scan_interval,
                                                     p_cfg->cpu_mask);
    }
    else
    {
        g_drv_ecc_scan_mode[DRV_SER_SCAN_TYPE_SBE] = DRV_ECC_SCAN_MODE_STOP;
    }

    if ((p_drv_ser_master->tcam_scan_en) && (p_cfg->tcam_scan_interval))
    {
        ret = drv_ser_set_mem_scan_mode(lchip, DRV_SER_SCAN_TYPE_TCAM,
                                                     (p_cfg->tcam_scan_interval != 0),
                                                     p_cfg->tcam_scan_interval,
                                                     p_cfg->cpu_mask);
    }
    else
    {
        g_drv_ecc_scan_mode[DRV_SER_SCAN_TYPE_TCAM] = DRV_ECC_SCAN_MODE_STOP;
    }

    if (ret)
    {
        mem_free(p_drv_ser_master);
        return DRV_E_INIT_FAILED;
    }

    return DRV_E_NONE;
}

int32
drv_ser_deinit(uint8 lchip)
{
    drv_ser_master_t* p_drv_ser_master = NULL;

    p_drv_ser_master = (drv_ser_master_t*)(p_drv_master[lchip]->p_ser_master);
    if ((SDK_WORK_PLATFORM == 1) || (!p_drv_ser_master))
    {
        return DRV_E_NONE;
    }

    /*step1: stop all scan task*/
    g_drv_ecc_scan_mode[DRV_SER_SCAN_TYPE_SBE] = DRV_ECC_SCAN_MODE_STOP;
    g_drv_ecc_scan_mode[DRV_SER_SCAN_TYPE_TCAM] = DRV_ECC_SCAN_MODE_STOP;
    do
    {
        if ((p_drv_ser_master->scan_doing[DRV_SER_SCAN_TYPE_SBE] == 0)
            &&(p_drv_ser_master->scan_doing[DRV_SER_SCAN_TYPE_TCAM] == 0))
        {
            break;
        }
    }
    while (1);
    if (p_drv_ser_master->scan_thread[DRV_SER_SCAN_TYPE_SBE].p_scan_task)
    {
        sal_task_destroy(p_drv_ser_master->scan_thread[DRV_SER_SCAN_TYPE_SBE].p_scan_task);
    }
    /*step2: mem free*/
    if (p_drv_ser_master)
    {
        mem_free(p_drv_ser_master);
        p_drv_ser_master = NULL;
    }

    //drv_ser_db_deinit( lchip);
    return DRV_E_NONE;
}

int32
drv_ser_set_cfg(uint8 lchip, uint32 type,void * p_cfg)
{
    if (type != DRV_SER_CFG_TYPE_HW_RESER_EN)
    {
        DRV_PTR_VALID_CHECK(p_cfg);
    }
    switch (type)
    {
    case DRV_SER_CFG_TYPE_SCAN_MODE:
    {
        drv_ser_scan_info_t *p_scan_cfg = (drv_ser_scan_info_t*) p_cfg;
        DRV_IF_ERROR_RETURN(drv_ser_set_mem_scan_mode(lchip,p_scan_cfg->type, p_scan_cfg->mode,   p_scan_cfg->scan_interval,0));
    }
        break;
    case DRV_SER_CFG_TYPE_TCAM_SCAN_INFO:
    {
        drv_ser_scan_info_t *p_scan_cfg = (drv_ser_scan_info_t*) p_cfg;
        DRV_IF_ERROR_RETURN(drv_ser_set_tcam_scan_cfg(lchip, p_scan_cfg->burst_entry_num, p_scan_cfg->burst_interval));
    }
        break;
    case DRV_SER_CFG_TYPE_ECC_EVENT_CB:
    {
        drv_ser_master_t* p_drv_ser_master = (drv_ser_master_t*)(p_drv_master[lchip]->p_ser_master);
        if(p_drv_ser_master )
        p_drv_ser_master->ser_event_cb = p_cfg;
    }
        break;

    case DRV_SER_CFG_TYPE_HW_RESER_EN:
        return drv_sdb_set_hw_reset_en( lchip, 1);
    case DRV_SER_CFG_TYPE_DMA_RECOVER_TCAM:
        drv_ser_dma_recover_tcam(lchip, p_cfg);
        break;
    default:
        return DRV_E_NONE;
    }
    return DRV_E_NONE;
}


int32
drv_ser_get_cfg(uint8 lchip, uint32 type,void * p_cfg)
{
    if ((type != DRV_SER_CFG_TYPE_SHOW_SER_STAUTS) && (type != DRV_SER_CFG_TYPE_SCAN_MODE))
    {
        DRV_PTR_VALID_CHECK(p_cfg);
    }

    switch (type)
    {
    case DRV_SER_CFG_TYPE_SCAN_MODE:
    {
        if (p_cfg)
        {
            drv_ser_scan_info_t *p_scan_cfg = (drv_ser_scan_info_t*) p_cfg;
            drv_ser_get_mem_scan_mode( lchip , p_scan_cfg->type, &p_scan_cfg->mode, &p_scan_cfg->scan_interval);
        }
        else
        {
            return drv_ser_get_tcam_scan_enable(lchip);
        }
    }
        break;
    case DRV_SER_CFG_TYPE_ECC_INTERRUPT_INFO:
        DRV_IF_ERROR_RETURN(drv_ser_get_intr_info(lchip,p_cfg, 0));
        break;
    case DRV_SER_CFG_TYPE_SHOW_SER_STAUTS:
        DRV_IF_ERROR_RETURN(drv_ser_show_status(lchip));
        break;
    case DRV_SER_CFG_TYPE_HW_RESER_EN:
    {
        drv_sdb_t* p_sdb =  g_sdb_master[lchip];
        if (NULL == p_sdb)
        {
            *(uint32*)p_cfg = 0;
        }
        else
        {
            *(uint32*)p_cfg = p_sdb->hw_reset_status;
        }
    }
        break;
    default:
        return DRV_E_NONE;
    }
    return DRV_E_NONE;
}


int32
drv_ser_register_hw_reset_cb(uint8 lchip, uint32 cb_type, drv_ser_hw_reset_cb func)
{
    drv_sdb_t* p_sdb = NULL;

    p_sdb = g_sdb_master[lchip];

    if ((SDK_WORK_PLATFORM == 1) || (NULL ==  g_sdb_master[lchip]))
    {
        return DRV_E_NONE;
    }

    if ((cb_type >= DRV_SER_HW_RESET_CB_TYPE_NUM) )
    {
        return DRV_E_INVALID_PARAMETER;
    }

    if (p_sdb->reset_hw_cb[cb_type])/*2nd GO TO */
    {
        return DRV_E_NONE;
    }

    p_sdb->reset_hw_cb[cb_type] = func;

    return DRV_E_NONE;
}

int32
drv_ser_register_dma_data_memory_cb(uint8 lchip, drv_ser_get_data_memory_cb func)
{
#if (SDK_WORK_PLATFORM == 0)
    drv_sdb_t* p_sdb = NULL;

    p_sdb = g_sdb_master[lchip];

    if (NULL == p_sdb)
    {
        return DRV_E_NONE;
    }

    p_sdb->get_dma_data_memory_cb = func;
#endif
    return DRV_E_NONE;
}

